#include <IrisQuery.h>
#include "FunTrace.h"
#include <aknglobalnote.h>
#include <e32math.h>
#include <eikimage.h>
#include <akndialog.h>
#include <aknquerycontrol.h>
#include <aknnumedwin.h>
#include <es_sock.h>
#include <SingaporeBus.rsg>
#include <aknquerydialog.h>

const TInt DndTimedOut = -5120;
const TInt kIrisTimeout = 45*1000000;
const TInt kCrowdIrisTimeout = 10*1000000;

#define EAknEditorFlagEnablePartialScreen             0x200000

#include <ImageConversion.h>
#include <euserhl.h>
#include "Binder.h"

static TBool IsSpace(TChar ch)
	{
	switch(ch)
		{
		case ' ': case '\n': case '\t': case '\r':
			return ETrue;
			break;
		default:
			return EFalse;
		}
	}

static TPtrC8 IrisTrim( const TDesC8& aBuf)
	{
	TInt beg, end;
	for(beg = 0 ; beg < aBuf.Length() && IsSpace( aBuf[beg] ) ; ++beg);
	if(beg == aBuf.Length()) return aBuf.Mid(0, 0);
	for(end = aBuf.Length() - 1 ; end > beg && IsSpace( aBuf[end] ) ; --end);
	return aBuf.Mid(beg, end + 1 - beg);
	}


static TPtrC8 IrisExtractField(const TDesC8& aPrefix, const TDesC8& aSuffix, TPtrC8& aBuf)
	{
	TFunTrace funTrace(__PRETTY_FUNCTION__);
	TPtrC8 ret;
	TInt begfield = aBuf.Find(aPrefix);
	if(begfield != KErrNotFound)
		{
		TInt endfield = aBuf.Mid(begfield + aPrefix.Length()).Find(aSuffix);
		if(endfield != KErrNotFound)
			{
			ret.Set( aBuf.Mid(begfield + aPrefix.Length(), endfield) );
			aBuf.Set( aBuf.Mid( begfield + aPrefix.Length() + endfield + aSuffix.Length() ) );
			return ret;
			}
		}
	aBuf.Set( aBuf.Mid( aBuf.Length() ) );
	return ret;
	}

static void PrintNoteL(TRefByValue<const TDesC> aFormat, ...)
    {
    VA_LIST list;
    VA_START(list, aFormat);
    TBuf<256> buf;
    buf.FormatList(aFormat, list);
    VA_END(list);
	CAknGlobalNote* globalNote = CAknGlobalNote::NewLC();
	globalNote->ShowNoteL(EAknGlobalInformationNote, buf); 
    CleanupStack::PopAndDestroy(globalNote);
    }


_LIT(kFormatRequestPending, "\trequesting...");
_LIT(kFormatRequestScheduled, "\tqueued, select to request");
_LIT(kFormatRequestScheduledWaitingConnection, "\tqueued, waiting connection");
_LIT(kFormatRequestWait, "\tselect to request");
_LIT(kFormatRequestSchedule, "\tevery %S");
_LIT(kFormatRequestCompleted, "\t%S \xf814 %S");
_LIT(kFormatRequestBlocked, "\tunexpected answer (probably blocked by SBS or SMRT), please check whether the app has been updated");
_LIT(kFormatRequestPendingCaptcha, "\trequesting captcha...");
_LIT(kFormatRequestDownloadingCaptcha, "\tdownloading captcha...");
_LIT(kFormatCaptchaError, "\tcaptcha processing error");
_LIT(kFormatRequestSubmittingCaptcha, "\tsubmitting captcha...");
_LIT(kFormatSolvingCaptcha, "\tsolving captcha...");
_LIT(kFormatRequestError, "\terror (%S, %S)");
_LIT(kFormatRequestUnavailable, "\tschedule unavailable");
_LIT(kFormatRequestPendingInitialization, "\twaiting for initialization...");
_LIT(kFormatRequestPendingToken, "\trequesting token...");
_LIT(kFormatRequestPendingCrowdToken, "\trequesting crowd token...");
_LIT(kFormatRequestSelectingBus, "\tselecting bus...");



/**
 * First phase of Symbian two-phase construction. Should not contain any
 * code that could leave.
 */
CIrisSession::CIrisSession()
	{
	TFunTrace funTrace(__PRETTY_FUNCTION__);
	iIrisTimeoutTimer.CreateLocal();
	iCrowdIrisTimeoutTimer.CreateLocal();
	iIrisTimeoutTimerHelper = NULL;
	iCrowdIrisTimeoutTimerHelper = NULL;
	iIrisCaptchaActionPage = NULL;
	
	iIrisToken = NULL;
	iIrisRlStickyKey = NULL;
	iIrisToken = NULL;
	
	iIrisCaptchaDialog = NULL;

	}

CIrisSession::~CIrisSession()
	{
	
	TFunTrace funTrace(__PRETTY_FUNCTION__);
	
	delete iIrisRlStickyKey;
	delete iIrisToken;
	delete iIrisCaptchaActionPage;
	delete iIrisTimeoutTimerHelper;
	delete iCrowdIrisTimeoutTimerHelper;
	iIrisTimeoutTimer.Close();
	iCrowdIrisTimeoutTimer.Close();
	iIrisTokenTransaction.Close();
	iIrisCaptchaTransaction.Close();
	for(TInt i = 0 ; i < iIrisQueries.Count() ; ++i)
		delete iIrisQueries[i];
	iIrisQueries.Close();
	iHTTPSession.Close();
	}

CIrisSession* CIrisSession::NewL()
	{
TFunTrace funTrace(__PRETTY_FUNCTION__);
	CIrisSession* self = CIrisSession::NewLC();
	CleanupStack::Pop( self );
	return self;
	}

CIrisSession* CIrisSession::NewLC()
	{
TFunTrace funTrace(__PRETTY_FUNCTION__);
	CIrisSession* self = new ( ELeave ) CIrisSession();
	CleanupStack::PushL( self );
	self->ConstructL();
	return self;
	}


void CIrisSession::NotifyConnected()
	{
	TFunTrace funTrace(__PRETTY_FUNCTION__);
	for(TInt i = 0 ; i < iIrisQueries.Count() ; ++i)
		if(iIrisQueries[i]->iRequestStatus == CIrisQuery::ERequestError)
			SubmitL(iIrisQueries[i]);
	}

void CIrisSession::CloseConnectionL()
	{
	TFunTrace funTrace(__PRETTY_FUNCTION__);
	CancelAllIrisRequestsL();
	for(TInt i = 0 ; i < iIrisQueries.Count() ; ++i)
		if( (iIrisQueries[i]->iRequestStatus == CIrisQuery::ERequestPending || iIrisQueries[i]->iRequestStatus == CIrisQuery::ERequestPendingInitialization))
			{
			_LIT8 (connectionClosed, "connection closed");
			iIrisQueries[i]->iRequestStatus = CIrisQuery::ERequestError;
			(*iIrisQueries[i]->iCallback.Get())(iIrisQueries[i], (*iIrisQueries[i]->iStationNumber), (*iIrisQueries[i]->iServiceName), CIrisQuery::ERequestError, (*&kFormatRequestError()), (*&connectionClosed), (*&connectionClosed));
			}
	iHTTPSession.Close();
	}



void CIrisSession::SetConnectionInfoL(const RConnection& aConnection, const RSocketServ& aSocketServ)
	{
	TFunTrace funTrace(__PRETTY_FUNCTION__);
	iHTTPSession.OpenL();
	RStringPool strP = iHTTPSession.StringPool();
	RHTTPConnectionInfo connInfo = iHTTPSession.ConnectionInfo();
	connInfo.SetPropertyL ( strP.StringF(HTTP::EHttpSocketServ, RHTTPSession::GetTable() ), THTTPHdrVal (aSocketServ.Handle()) );
	TInt connPtr = REINTERPRET_CAST(TInt, &aConnection);
	connInfo.SetPropertyL ( strP.StringF(HTTP::EHttpSocketConnection, RHTTPSession::GetTable() ), THTTPHdrVal (connPtr) );
	_LIT8(KUserAgent, "SBSTransitIris/60 CFNetwork/485.12.7 Darwin/10.4.0");
	_LIT8(KAccept, "*/*");
	RHTTPSessionSetHeaderL(iHTTPSession, HTTP::EUserAgent, KUserAgent);
	RHTTPSessionSetHeaderL(iHTTPSession, HTTP::EAccept, KAccept);
	}

void CIrisSession::ConstructL()
	{
TFunTrace funTrace(__PRETTY_FUNCTION__);
	iIrisTimeoutTimerHelper = CActiveHelper<RTimer*>::NewL();
	iCrowdIrisTimeoutTimerHelper = CActiveHelper<RTimer*>::NewL();
	
	iIrisInitalizationCycle = EFalse;
	iIrisTokenTransactionTarget = CHTTPTransactionTarget::NewL();
	iIrisCaptchaTransactionTarget = CHTTPTransactionTarget::NewL();
	iIrisCaptchaTransactionSource = new (ELeave) CHTTPTransactionSource;

	iCrowdIrisTokenTransactionTarget = CHTTPTransactionTarget::NewL();
	
	iCrowdIrisTokenUpdateTransactionTarget = CHTTPTransactionTarget::NewL();
	iCrowdIrisTokenUpdateTransactionTarget->SetRun( scalp::MakeFunctionL( scalp::Bind(&CIrisSession::ReceivedCrowdIrisTokenUpdateAnswerL, this, scalp::Free1, scalp::Free2, scalp::Free3, scalp::Free4) ) );

	iCrowdIrisToken = EFalse;
	

	TTime now;
	now.UniversalTime();
	TInt64 iSeed = now.Int64();
	iCrowdIrisTokenId = Math::Rand(iSeed) % 100;
	
	
	iLastFailureIrisApi = Time::MinTTime(); // beginnings of time...
	iLastFailureCrowdIrisToken = Time::MinTTime();
	
	}


void CIrisSession::Cancel(CIrisQuery* aQuery)
	{
	TFunTrace funTrace(__PRETTY_FUNCTION__);
	if(iIrisInitalizationCycle && aQuery == iIrisInitializationPilotService)
		{
		IrisTransactionError(aQuery, KErrCancel, RHTTPTransaction());
		if(iIrisCaptchaDecoderTarget.Get()) iIrisCaptchaDecoderTarget->Cancel();
		if(iIrisCaptchaBitmapScalerTarget.Get()) iIrisCaptchaBitmapScalerTarget->Cancel();
		if(iIrisTokenTransaction != RHTTPTransaction())
			{
			iIrisTokenTransaction.Cancel();
			iIrisTokenTransaction.Close();
			iIrisTokenTransaction = RHTTPTransaction();
			}
		if(iCrowdIrisTokenTransaction != RHTTPTransaction())
			{
			iCrowdIrisTokenTransaction.Cancel();
			iCrowdIrisTokenTransaction.Close();
			iCrowdIrisTokenTransaction = RHTTPTransaction();
			}
		if(iCrowdIrisTokenUpdateTransaction != RHTTPTransaction())
			{
			iCrowdIrisTokenUpdateTransaction.Cancel();
			iCrowdIrisTokenUpdateTransaction.Close();
			iCrowdIrisTokenUpdateTransaction = RHTTPTransaction();
			}
		if(iIrisCaptchaTransaction != RHTTPTransaction())
			{
			iIrisCaptchaTransaction.Cancel();
			iIrisCaptchaTransaction.Close();
			iIrisCaptchaTransaction = RHTTPTransaction();
			}
		iCrowdIrisTimeoutTimerHelper->Cancel();
		iIrisInitalizationCycle = EFalse;
		}
	if(aQuery->iServiceTransaction != RHTTPTransaction())
		{
		aQuery->iServiceTransaction.Cancel();
		aQuery->iServiceTransaction.Close();
		aQuery->iServiceTransaction = RHTTPTransaction();
		}
	}

void CIrisSession::CancelAllIrisRequestsL()
	{
	TFunTrace funTrace(__PRETTY_FUNCTION__);
	if(iIrisCaptchaDecoderTarget.Get()) iIrisCaptchaDecoderTarget->Cancel();
	if(iIrisCaptchaBitmapScalerTarget.Get()) iIrisCaptchaBitmapScalerTarget->Cancel();
	if(iIrisTokenTransaction != RHTTPTransaction())
		{
		iIrisTokenTransaction.Cancel();
		iIrisTokenTransaction.Close();
		iIrisTokenTransaction = RHTTPTransaction();
		}
	if(iCrowdIrisTokenTransaction != RHTTPTransaction())
		{
		iCrowdIrisTokenTransaction.Cancel();
		iCrowdIrisTokenTransaction.Close();
		iCrowdIrisTokenTransaction = RHTTPTransaction();
		}
	if(iCrowdIrisTokenUpdateTransaction != RHTTPTransaction())
		{
		iCrowdIrisTokenUpdateTransaction.Cancel();
		iCrowdIrisTokenUpdateTransaction.Close();
		iCrowdIrisTokenUpdateTransaction = RHTTPTransaction();
		}
	if(iIrisCaptchaTransaction != RHTTPTransaction())
		{
		iIrisCaptchaTransaction.Cancel();
		iIrisCaptchaTransaction.Close();
		iIrisCaptchaTransaction = RHTTPTransaction();
		}
	for(TInt i = 0 ; i < iIrisQueries.Count() ; ++i)
		if(iIrisQueries[i]->iServiceTransaction != RHTTPTransaction())
			{
			iIrisQueries[i]->iServiceTransaction.Cancel();
			iIrisQueries[i]->iServiceTransaction.Close();
			iIrisQueries[i]->iServiceTransaction = RHTTPTransaction();
			}
	iIrisInitalizationCycle = EFalse;
	iCrowdIrisTimeoutTimerHelper->Cancel();
	iIrisTimeoutTimerHelper->Cancel();
	}


TBool CIrisSession::AllRequestsCompleted() const
{
TFunTrace funTrace(__PRETTY_FUNCTION__);

	if(iIrisCaptchaTransaction != RHTTPTransaction()) return EFalse;
	if(iIrisTokenTransaction != RHTTPTransaction()) return EFalse;
	for(TInt i = 0 ; i < iIrisQueries.Count() ; ++i)
		if(iIrisQueries[i]->iServiceTransaction != RHTTPTransaction())
			return EFalse;
	return ETrue;
}


void CIrisSession::SubmitIrisApiRequestL(CIrisQuery* aQuery)
	{
	TFunTrace funTrace(__PRETTY_FUNCTION__);
	
	TBuf8<10> stationNumber(*aQuery->iStationNumber);
	TBuf8<1024> uristr;
	uristr.Format(
#include "iris_query.txt"
			, aQuery->iServiceName, &stationNumber);
	if(aQuery->iServiceTransaction != RHTTPTransaction())
		{
		aQuery->iServiceTransaction.Cancel();
		aQuery->iServiceTransaction.Close();
		}
	delete aQuery->iServiceTransactionTarget;
	aQuery->iServiceTransactionTarget = CHTTPTransactionTarget::NewL();
	aQuery->iServiceTransactionTarget->SetRun( scalp::MakeFunctionL( scalp::Bind(&CIrisSession::ReceivedIrisApiAnswerL, this, aQuery, scalp::Free1, scalp::Free2, scalp::Free3, scalp::Free4) ) );
	aQuery->iServiceTransactionTarget->SetRunBodyData(NULL);
	aQuery->iServiceTransactionTarget->SetRunError( scalp::MakeFunctionL( scalp::Bind(&CIrisSession::IrisApiTransactionError, this, aQuery, scalp::Free1, scalp::Free2) ) );			
	aQuery->iServiceTransaction = RHTTPSessionOpenTransactionL(iHTTPSession, uristr, *aQuery->iServiceTransactionTarget, HTTP::EGET);
	if(iIrisRlStickyKey)
		RHTTPRequestSetCookie(iHTTPSession, aQuery->iServiceTransaction.Request(), _L8("rl-sticky-key"), *iIrisRlStickyKey);
	
	{
		// faster without pipelining
		RStringPool strP = iHTTPSession.StringPool();
		const TStringTable& stringTable = RHTTPSession::GetTable();
		RStringF httpPipelining = strP.StringF( HTTP::EHttpPipelining, stringTable );
		THTTPHdrVal disablePipelining = strP.StringF( HTTP::EDisablePipelining, stringTable );
		aQuery->iServiceTransaction.PropertySet().RemoveProperty( httpPipelining );
		aQuery->iServiceTransaction.PropertySet().SetPropertyL( httpPipelining, disablePipelining );
	}
	
	aQuery->iServiceTransaction.SubmitL();
	aQuery->iRequestStatus = CIrisQuery::ERequestPending;
	(*aQuery->iCallback.Get())(aQuery, (*aQuery->iStationNumber), (*aQuery->iServiceName), CIrisQuery::ERequestPending, (kFormatRequestPending()), (KNullDesC8()), (KNullDesC8()));
	iIrisTimeoutTimerHelper->Cancel();
	iIrisTimeoutTimer.After(iIrisTimeoutTimerHelper->iStatus, kIrisTimeout);
	iIrisTimeoutTimerHelper->SetActive(this, &iIrisTimeoutTimer);
	}


void CIrisSession::SubmitIrisMobresultRequestL(CIrisQuery* aQuery)
	{
	TFunTrace funTrace(__PRETTY_FUNCTION__);
	
	TBuf8<1024> uristr;
	if(aQuery->iStationInterchange)
		uristr.Format(_L8("http://www.sbstransit.com.sg/mobileiris/%S/mobresult_dep.aspx?intcode=%S&svc=%0*S&dispsvc=%0*S"), iIrisToken, &aQuery->iStationNumber->Left(aQuery->iStationNumber->Length()-1), Max(3, aQuery->iServiceName->Length()), aQuery->iServiceName, Max(3, aQuery->iServiceName->Length()), aQuery->iServiceName);
	else
		{
		TInt servicePadding = 3;
		if((*aQuery->iServiceName)[aQuery->iServiceName->Length()-1] < '0' || (*aQuery->iServiceName)[aQuery->iServiceName->Length()-1] > '9')
			++servicePadding;
		uristr.Format(_L8("http://www.sbstransit.com.sg/mobileiris/%S/index_mobresult.aspx?stop=%S&svc=%0*S"), iIrisToken, aQuery->iStationNumber, Max(servicePadding, aQuery->iServiceName->Length()), aQuery->iServiceName);
		}
	if(aQuery->iServiceTransaction != RHTTPTransaction())
		{
		aQuery->iServiceTransaction.Cancel();
		aQuery->iServiceTransaction.Close();
		}
	delete aQuery->iServiceTransactionTarget;
	aQuery->iServiceTransactionTarget = CHTTPTransactionTarget::NewL();
	aQuery->iServiceTransactionTarget->SetRun( scalp::MakeFunctionL( scalp::Bind(&CIrisSession::ReceivedIrisMobresultAnswerL, this, aQuery, scalp::Free1, scalp::Free2, scalp::Free3, scalp::Free4) ) );
	aQuery->iServiceTransactionTarget->SetRunBodyData(NULL);
	aQuery->iServiceTransactionTarget->SetRunError( scalp::MakeFunctionL( scalp::Bind(&CIrisSession::IrisTransactionError, this, aQuery, scalp::Free1, scalp::Free2) ) );			
	aQuery->iServiceTransaction = RHTTPSessionOpenTransactionL(iHTTPSession, uristr, *aQuery->iServiceTransactionTarget, HTTP::EGET);
	if(iIrisRlStickyKey)
		RHTTPRequestSetCookie(iHTTPSession, aQuery->iServiceTransaction.Request(), _L8("rl-sticky-key"), *iIrisRlStickyKey);
	
	{
		// faster without pipelining
		RStringPool strP = iHTTPSession.StringPool();
		const TStringTable& stringTable = RHTTPSession::GetTable();
		RStringF httpPipelining = strP.StringF( HTTP::EHttpPipelining, stringTable );
		THTTPHdrVal disablePipelining = strP.StringF( HTTP::EDisablePipelining, stringTable );
		aQuery->iServiceTransaction.PropertySet().RemoveProperty( httpPipelining );
		aQuery->iServiceTransaction.PropertySet().SetPropertyL( httpPipelining, disablePipelining );
	}
	
	aQuery->iServiceTransaction.SubmitL();
	aQuery->iRequestStatus = CIrisQuery::ERequestPending;
	(*aQuery->iCallback.Get())(aQuery, (*aQuery->iStationNumber), (*aQuery->iServiceName), CIrisQuery::ERequestPending, (*&kFormatRequestPending()), (*&KNullDesC8()), (*&KNullDesC8()));
	iIrisTimeoutTimerHelper->Cancel();
	iIrisTimeoutTimer.After(iIrisTimeoutTimerHelper->iStatus, kIrisTimeout);
	iIrisTimeoutTimerHelper->SetActive(this, &iIrisTimeoutTimer);
	}

TInt CIrisSession::IrisTransactionError(CIrisQuery* aQuery, TInt aError, RHTTPTransaction aTransaction)
	{
	TFunTrace funTrace(__PRETTY_FUNCTION__);
	//REMOVED if(aTransaction != RHTTPTransaction()) aTransaction.Cancel();
	//REMOVED LCleanedupRef<RHTTPTransaction> cleanupTransaction(aTransaction);
	TBuf8<64> lastErrorStr, statusCodeStr;
	lastErrorStr.Format(_L8("%d"), aError);
	statusCodeStr.Format(_L8("%d"), iIrisStatusCode);
	
	if(iIrisInitalizationCycle)
		{
		iIrisInitalizationCycle = EFalse;
		for(TInt i = 0 ; i < iIrisQueries.Count() ; ++i)
			if(( iIrisQueries[i]->iRequestStatus == CIrisQuery::ERequestPending || iIrisQueries[i]->iRequestStatus == CIrisQuery::ERequestPendingInitialization ) ) 
				{
				iIrisQueries[i]->iRequestStatus = CIrisQuery::ERequestError;
				(*iIrisQueries[i]->iCallback.Get())(iIrisQueries[i], (*iIrisQueries[i]->iStationNumber), (*iIrisQueries[i]->iServiceName), CIrisQuery::ERequestError, (*&kFormatRequestError()), (*&lastErrorStr), (*&statusCodeStr));
				}
		}
	else
		{
		aQuery->iRequestStatus = CIrisQuery::ERequestError;
		(*aQuery->iCallback.Get())(aQuery, (*aQuery->iStationNumber), (*aQuery->iServiceName), CIrisQuery::ERequestError, (*&kFormatRequestError()), (*&lastErrorStr), (*&statusCodeStr));
		}
	
	return KErrNone;
	}

void CIrisSession::SubmitCrowdIrisTokenRequestL()
	{
	TFunTrace funTrace(__PRETTY_FUNCTION__);
	TBuf8<1024> url;
	url.Format(_L8("http://singapore-bus.appspot.com/getIrisToken?id=%d"), iCrowdIrisTokenId);
	if(iCrowdIrisTokenTransaction != RHTTPTransaction())
		{
		iCrowdIrisTokenTransaction.Cancel();
		iCrowdIrisTokenTransaction.Close();
		}
	iCrowdIrisTokenTransactionTarget->SetRun( scalp::MakeFunctionL( scalp::Bind(&CIrisSession::ReceivedCrowdIrisTokenAnswerL, this, scalp::Free1, scalp::Free2, scalp::Free3, scalp::Free4) ) );
	iCrowdIrisTokenTransactionTarget->SetRunError( scalp::MakeFunctionL( scalp::Bind(&CIrisSession::CrowdIrisTransactionError, this, iIrisInitializationPilotService, scalp::Free1, scalp::Free2) ) );
	iCrowdIrisTokenTransaction = RHTTPSessionOpenTransactionL(iHTTPSession, url, *iCrowdIrisTokenTransactionTarget, HTTP::EGET);
	iCrowdIrisTokenTransaction.SubmitL();
	iCrowdIrisToken = ETrue;
	iIrisInitializationPilotService->iRequestStatus = CIrisQuery::ERequestPendingInitialization;
	(*iIrisInitializationPilotService->iCallback.Get())(iIrisInitializationPilotService, (*iIrisInitializationPilotService->iStationNumber), (*iIrisInitializationPilotService->iServiceName), CIrisQuery::ERequestPendingInitialization, (*&kFormatRequestPendingCrowdToken()), (*&KNullDesC8()), (*&KNullDesC8()));
	iCrowdIrisTimeoutTimerHelper->Cancel();
	iCrowdIrisTimeoutTimer.After(iCrowdIrisTimeoutTimerHelper->iStatus, kCrowdIrisTimeout);
	iCrowdIrisTimeoutTimerHelper->SetActive(this, &iCrowdIrisTimeoutTimer);
	}

void CIrisSession::SubmitCrowdIrisTokenUpdateRequestL()
	{
	TFunTrace funTrace(__PRETTY_FUNCTION__);
	TBuf8<1024> url;
	url.Format(_L8("http://singapore-bus.appspot.com/setIrisToken?id=%d&value=%S&rlStickyKey=%S"), iCrowdIrisTokenId, iIrisToken, iIrisRlStickyKey ? iIrisRlStickyKey : &KNullDesC8());
	if(iCrowdIrisTokenUpdateTransaction != RHTTPTransaction())
		{
		iCrowdIrisTokenUpdateTransaction.Cancel();
		iCrowdIrisTokenUpdateTransaction.Close();
		}
	iCrowdIrisTokenUpdateTransaction = RHTTPSessionOpenTransactionL(iHTTPSession, url, *iCrowdIrisTokenUpdateTransactionTarget, HTTP::EGET);
	iCrowdIrisTokenUpdateTransaction.SubmitL();
	}

void CIrisSession::ReceivedCrowdIrisTokenUpdateAnswerL(RHTTPTransaction aTransaction, THTTPEvent aEvent, TInt aLastError, TPtrC8 aBuf)
	{
	TFunTrace funTrace(__PRETTY_FUNCTION__);
	iCrowdIrisTokenUpdateTransaction = RHTTPTransaction();
	aTransaction.Cancel();
	aTransaction.Close();
	}


void CIrisSession::ReceivedCrowdIrisTokenAnswerL(RHTTPTransaction aTransaction, THTTPEvent aEvent, TInt aLastError, TPtrC8 aBuf)
	{
	TFunTrace funTrace(__PRETTY_FUNCTION__);

	iCrowdIrisTimeoutTimerHelper->Cancel();
	iCrowdIrisTokenTransaction = RHTTPTransaction();
	iIrisStatusCode = aTransaction.Response().StatusCode();
	if(aEvent.iStatus != THTTPEvent::ESucceeded || iIrisStatusCode != 200)
		User::Leave(aLastError < 0 ? aLastError : KErrAbort);

	TInt sepLoc = aBuf.Locate(' ');
	if(sepLoc == KErrNotFound) User::Leave(KErrNotFound);
	if(sepLoc == 0) User::Leave(KErrNotFound);
	if(sepLoc == aBuf.Length()-1) User::Leave(KErrNotFound);
	delete iIrisToken;
	iIrisToken = aBuf.Left(sepLoc).AllocL();
	delete iIrisRlStickyKey;
	if(sepLoc+1 < aBuf.Length() - 1)
		iIrisRlStickyKey = aBuf.Mid(sepLoc+1).AllocL();
	else 
		iIrisRlStickyKey = NULL;
	SubmitIrisMobresultRequestL(iIrisInitializationPilotService);
	aTransaction.Cancel();
	aTransaction.Close(); // note: if a panic is raised before reaching this line, MHFRunError will close the transaction
	}

TInt CIrisSession::CrowdIrisTransactionError(CIrisQuery* aQuery, TInt aError, RHTTPTransaction aTransaction)
	{
	TFunTrace funTrace(__PRETTY_FUNCTION__);
	//REMOVED aTransaction.Cancel();
	//REMOVED LCleanedupRef<RHTTPTransaction> cleanupTransaction(aTransaction);
	
	SubmitIrisTokenRequestL();

	return KErrNone;
	}



void CIrisSession::SubmitIrisTokenRequestL()
	{
	TFunTrace funTrace(__PRETTY_FUNCTION__);
	if(iIrisTokenTransaction != RHTTPTransaction())
		{
		iIrisTokenTransaction.Cancel();
		iIrisTokenTransaction.Close();
		}
	iIrisTokenTransactionTarget->SetRun( scalp::MakeFunctionL( scalp::Bind(&CIrisSession::ReceivedIrisTokenAnswerL, this, scalp::Free1, scalp::Free2, scalp::Free3, scalp::Free4) ) );
	iIrisTokenTransactionTarget->SetRunError( scalp::MakeFunctionL( scalp::Bind(&CIrisSession::IrisTransactionError, this, iIrisInitializationPilotService, scalp::Free1, scalp::Free2) ) );
	iIrisTokenTransaction = RHTTPSessionOpenTransactionL(iHTTPSession, _L8("http://www.sbstransit.com.sg/mobileiris/"), *iIrisTokenTransactionTarget, HTTP::EGET);
	
	{
		// faster without pipelining
		RStringPool strP = iHTTPSession.StringPool();
		const TStringTable& stringTable = RHTTPSession::GetTable();
		RStringF httpPipelining = strP.StringF( HTTP::EHttpPipelining, stringTable );
		THTTPHdrVal disablePipelining = strP.StringF( HTTP::EDisablePipelining, stringTable );
		iIrisTokenTransaction.PropertySet().RemoveProperty( httpPipelining );
		iIrisTokenTransaction.PropertySet().SetPropertyL( httpPipelining, disablePipelining );
	}
	
	iIrisTokenTransaction.SubmitL();
	iCrowdIrisToken = EFalse;
	iIrisInitializationPilotService->iRequestStatus = CIrisQuery::ERequestPendingInitialization;
	(*iIrisInitializationPilotService->iCallback.Get())(iIrisInitializationPilotService, (*iIrisInitializationPilotService->iStationNumber), (*iIrisInitializationPilotService->iServiceName), CIrisQuery::ERequestPendingInitialization, (*&kFormatRequestPendingToken()), (*&KNullDesC8()), (*&KNullDesC8()));
	iIrisTimeoutTimerHelper->Cancel();
	iIrisTimeoutTimer.After(iIrisTimeoutTimerHelper->iStatus, kIrisTimeout);
	iIrisTimeoutTimerHelper->SetActive(this, &iIrisTimeoutTimer);
	}

void CIrisSession::ReceivedIrisTokenAnswerL(RHTTPTransaction aTransaction, THTTPEvent aEvent, TInt aLastError, TPtrC8 aBuf)
	{
	TFunTrace funTrace(__PRETTY_FUNCTION__);

	iIrisTimeoutTimerHelper->Cancel();
	iIrisTokenTransaction = RHTTPTransaction();
	iIrisStatusCode = aTransaction.Response().StatusCode();
	if(aEvent.iStatus != THTTPEvent::ESucceeded || iIrisStatusCode != 200)
		User::Leave(aLastError < 0 ? aLastError : KErrAbort);

	delete iIrisRlStickyKey;
	iIrisRlStickyKey = RHTTPRequestGetCookie(iHTTPSession, aTransaction.Response(), _L8("rl-sticky-key"));
	delete iIrisToken;
	{
	TPtrC8 buf = aTransaction.Request().URI().Extract(EUriPath);
	iIrisToken = IrisExtractField(_L8("/mobileiris/"), _L8("/"), buf).AllocL();
	}
	SubmitIrisMobresultRequestL(iIrisInitializationPilotService);
	aTransaction.Cancel();
	aTransaction.Close(); // note: if a panic is raised before reaching this line, MHFRunError will close the transaction
	}

static void IrisApiBusTranslation(const TDesC8& aSource, const TDesC8& aWab, TDes8& aDest)
	{
	if(aSource == _L8("-1"))
		aDest.Format(_L8("not operating now"));
	else if(aSource == _L8("-2"))
		aDest.Format(_L8("no prediction"));
	else if(aSource == _L8("0"))
		aDest.Format(_L8("Arriving"));
	else
		{
		aDest.Format(_L8("%S min"), &aSource);
		if(aWab == _L8("1"))
			aDest.AppendFormat(_L8("(WAB)"));
		}
	}

void CIrisSession::ReceivedIrisApiAnswerL(CIrisQuery* aQuery, RHTTPTransaction aTransaction, THTTPEvent aEvent, TInt aLastError, TPtrC8 aBuf)
	{
	TFunTrace funTrace(__PRETTY_FUNCTION__);
	
	iIrisTimeoutTimerHelper->Cancel();
	iIrisTimeoutTimer.After(iIrisTimeoutTimerHelper->iStatus, kIrisTimeout);
	iIrisTimeoutTimerHelper->SetActive(this, &iIrisTimeoutTimer);
	aQuery->iServiceTransaction = RHTTPTransaction();
	iIrisStatusCode = aTransaction.Response().StatusCode();
		
	if(aEvent.iStatus != THTTPEvent::ESucceeded || iIrisStatusCode != 200)
		User::Leave(aLastError < 0 ? aLastError : KErrAbort);

	if(aBuf.Find(_L8("</iris>")) == KErrNotFound)
		{
		User::Leave(KErrAbort);
		}
	
	if(aBuf.Find(_L8("<error><error_code>")) != KErrNotFound)
		{
		User::Leave(KErrAbort);
		}
		
	delete iIrisRlStickyKey;
	iIrisRlStickyKey = RHTTPRequestGetCookie(iHTTPSession, aTransaction.Response(), _L8("rl-sticky-key"));

	TPtrC8 buf (aBuf);
	TPtrC8 serviceName;
	for(serviceName.Set(IrisExtractField( _L8("<service_no>"), _L8("<"), buf )) ;
		serviceName.Length() ;
		serviceName.Set(IrisExtractField( _L8("<service_no>"), _L8("<"), buf ))
		)
		{
		TPtrC8 rawNextBus = IrisExtractField( _L8("<nextbus><t>"), _L8("<"), buf );
		TPtrC8 rawNextBusWab = IrisExtractField( _L8("<wab>"), _L8("<"), buf );
		TPtrC8 rawSubsequentBus = IrisExtractField( _L8("<subsequentbus><t>"), _L8("<"), buf );
		TPtrC8 rawSubsequentBusWab = IrisExtractField( _L8("<wab>"), _L8("<"), buf );
		TBuf8<256> nextBus, subSequentBus;
		IrisApiBusTranslation(rawNextBus, rawNextBusWab, nextBus);
		IrisApiBusTranslation(rawSubsequentBus, rawSubsequentBusWab, subSequentBus);
		if(serviceName.CompareF(*aQuery->iServiceName) == 0)
			{
			aQuery->iRequestStatus = CIrisQuery::ERequestCompleted;
			(*aQuery->iCallback.Get())(aQuery, (*aQuery->iStationNumber), (*&serviceName), CIrisQuery::ERequestCompleted, (*&kFormatRequestCompleted()), (*&nextBus), (*&subSequentBus));
			}
		}
	
	if(AllRequestsCompleted())
		{
		for(TInt i = 0 ; i < iIrisQueries.Count() ; ++i)
			if(iIrisQueries[i]->iRequestStatus == CIrisQuery::ERequestPending)
				{
				iIrisQueries[i]->iRequestStatus = CIrisQuery::ERequestUnavailable;
				(*iIrisQueries[i]->iCallback.Get())(iIrisQueries[i], (*iIrisQueries[i]->iStationNumber), (*iIrisQueries[i]->iServiceName), CIrisQuery::ERequestUnavailable, (*&kFormatRequestUnavailable()), (*&KNullDesC8()), (*&KNullDesC8()));	
				}
		}
		
	aTransaction.Cancel();
	aTransaction.Close(); // note: if a panic is raised before reaching this line, MHFRunError will close the transaction
	}

TInt CIrisSession::IrisApiTransactionError(CIrisQuery* aQuery, TInt aError, RHTTPTransaction aTransaction)
	{
	TFunTrace funTrace(__PRETTY_FUNCTION__);
	//REMOVED aTransaction.Cancel();
	//REMOVED LCleanedupRef<RHTTPTransaction> cleanupTransaction(aTransaction);
	
	
	if(1 == 0) // accept error
		{
		TBuf8<64> lastErrorStr, statusCodeStr;
		lastErrorStr.Format(_L8("%d"), aError);
		statusCodeStr.Format(_L8("%d"), iIrisStatusCode);
		aQuery->iRequestStatus = CIrisQuery::ERequestError;
		(*aQuery->iCallback.Get())(aQuery, (*aQuery->iStationNumber), (*aQuery->iServiceName), CIrisQuery::ERequestError, (*&kFormatRequestError()), (*&lastErrorStr), (*&statusCodeStr));
		}
	else // try a different method
		{
		iLastFailureIrisApi.HomeTime();
		SubmitL(aQuery);
		}
	
	return KErrNone;
	}


void CIrisSession::ReceivedIrisMobresultAnswerL(CIrisQuery* aQuery, RHTTPTransaction aTransaction, THTTPEvent aEvent, TInt aLastError, TPtrC8 aBuf)
	{
	
	TFunTrace funTrace(__PRETTY_FUNCTION__);
	
	
	iIrisTimeoutTimerHelper->Cancel();
	iIrisTimeoutTimer.After(iIrisTimeoutTimerHelper->iStatus, kIrisTimeout);
	iIrisTimeoutTimerHelper->SetActive(this, &iIrisTimeoutTimer);
	
	aQuery->iServiceTransaction = RHTTPTransaction();
	iIrisStatusCode = aTransaction.Response().StatusCode();
	if(aEvent.iStatus != THTTPEvent::ESucceeded || iIrisStatusCode != 200)
		User::Leave(aLastError < 0 ? aLastError : KErrAbort);

	{
		const TDesC8& path = aTransaction.Request().URI().Extract(EUriPath);
		if(path.Find(_L8("validation_page.aspx")) != KErrNotFound)
		{
		
		if(!iIrisInitalizationCycle) // captcha expired or we never provided any valid captcha
			{
			iIrisInitializationPilotService = aQuery;
			iIrisInitalizationCycle = ETrue;
			delete iIrisToken; // we go for a brand new token
			iIrisToken = NULL;
			SubmitCrowdIrisTokenRequestL();
			}
		else if (aQuery == iIrisInitializationPilotService && iCrowdIrisToken)
			{
			SubmitIrisTokenRequestL();
			}
		else if(aQuery == iIrisInitializationPilotService)
			{
			TPtrC8 buf(aBuf);
			delete iIrisCaptchaActionPage;
			iIrisCaptchaActionPage = IrisExtractField( _L8("action=\""), _L8("\">"), buf ).AllocL();
			TPtrC8 captchaUrl = IrisExtractField( _L8("<img src=\""), _L8("\" border"), buf );
			TBuf8<1024> url;
			url.Format(_L8("http://www.sbstransit.com.sg/mobileiris/%S/%S"), iIrisToken, &captchaUrl);
			if(iIrisCaptchaTransaction != RHTTPTransaction())
				{
				iIrisCaptchaTransaction.Cancel();
				iIrisCaptchaTransaction.Close();
				}
			iIrisCaptchaTransactionTarget->SetRun( scalp::MakeFunctionL( scalp::Bind(&CIrisSession::ReceivedIrisCaptchaAnswerL, this, scalp::Free1, scalp::Free2, scalp::Free3, scalp::Free4) ) );
			iIrisCaptchaTransactionTarget->SetRunError( scalp::MakeFunctionL( scalp::Bind(&CIrisSession::IrisTransactionError, this, aQuery, scalp::Free1, scalp::Free2) ) );
			iIrisCaptchaTransaction = RHTTPSessionOpenTransactionL(iHTTPSession, url, *iIrisCaptchaTransactionTarget, HTTP::EGET);
			if(iIrisRlStickyKey)
				RHTTPRequestSetCookie(iHTTPSession, iIrisCaptchaTransaction.Request(), _L8("rl-sticky-key"), *iIrisRlStickyKey);
			
			{
				// faster without pipelining
				RStringPool strP = iHTTPSession.StringPool();
				const TStringTable& stringTable = RHTTPSession::GetTable();
				RStringF httpPipelining = strP.StringF( HTTP::EHttpPipelining, stringTable );
				THTTPHdrVal disablePipelining = strP.StringF( HTTP::EDisablePipelining, stringTable );
				iIrisCaptchaTransaction.PropertySet().RemoveProperty( httpPipelining );
				iIrisCaptchaTransaction.PropertySet().SetPropertyL( httpPipelining, disablePipelining );
			}
			
			iIrisCaptchaTransaction.SubmitL();
			aQuery->iRequestStatus = CIrisQuery::ERequestPendingInitialization;
			(*aQuery->iCallback.Get())(aQuery, (*aQuery->iStationNumber), (*aQuery->iServiceName), CIrisQuery::ERequestPendingInitialization, (*&kFormatRequestPendingCaptcha()), (*&KNullDesC8()), (*&KNullDesC8()));
			}
		else
			{
			aQuery->iRequestStatus = CIrisQuery::ERequestPendingInitialization;
			(*aQuery->iCallback.Get())(aQuery, (*aQuery->iStationNumber), (*aQuery->iServiceName), CIrisQuery::ERequestPendingInitialization, (*&kFormatRequestPendingInitialization()), (*&KNullDesC8()), (*&KNullDesC8()));
			}
			
		}
	else if(path.Find(_L8("mobresult")) != KErrNotFound)
		{
		
		// =========
    	_LIT8(kNextBusPrefix, "Next bus:");
    	_LIT8(kSubsequentBusPrefix, "Subsequent bus:");
    	_LIT8(kServicePrefix, "Service ");
    	_LIT8(kbr, "<br>\r\n");
    			    	
		TPtrC8 buf = aBuf;
		for(;;)
    		{
			TPtrC8 servicename = *aQuery->iServiceName, nextBus, subSequentBus;
			TInt begserviceblock = buf.Find(kServicePrefix);
			if(begserviceblock != KErrNotFound)
				{
				buf.Set( buf.Mid(begserviceblock + kServicePrefix.iTypeLength) );
				TInt endservicename = buf.Locate('<');
				if(endservicename != KErrNotFound)
					{
					servicename.Set( buf.Left(endservicename) );
					buf.Set( buf.Mid(endservicename) );    					
					}
				}
			TInt begnextbus = buf.Find(kNextBusPrefix);
			if(begnextbus != KErrNotFound)
				{
				buf.Set( buf.Mid(begnextbus + kNextBusPrefix.iTypeLength) );
				TInt endnextbus = buf.Locate('<');
				if(endnextbus != KErrNotFound)
					{
					nextBus.Set( buf.Left(endnextbus) );
					buf.Set( buf.Mid(endnextbus) );    					
					}
				}					
			TInt begsubsequentbus = buf.Find(kSubsequentBusPrefix);
			if(begsubsequentbus != KErrNotFound)
				{
				buf.Set( buf.Mid(begsubsequentbus + kSubsequentBusPrefix.iTypeLength) );
				TInt endsubsequentbus = buf.Locate('<');
				if(endsubsequentbus != KErrNotFound)
					{
					subSequentBus.Set( buf.Left(endsubsequentbus) );
					buf.Set( buf.Mid(endsubsequentbus) );    					
					}
				}
			if(begserviceblock != KErrNotFound && begnextbus == KErrNotFound && begsubsequentbus == KErrNotFound)
				{
				TInt firstbr = buf.Find(kbr);
				if(firstbr != KErrNotFound)
					{
					buf.Set( buf.Mid(firstbr + kbr.iTypeLength) );
					TInt secondbr = buf.Find(kbr);
					if(secondbr != KErrNotFound)
						{
							nextBus.Set( buf.Left(secondbr) );
							buf.Set( buf.Mid(secondbr + kbr.iTypeLength) );
						}
					}
				}
			if( (nextBus.Length() || subSequentBus.Length()) )
				{
				if(servicename.CompareF(*aQuery->iServiceName) == 0)
					{
					aQuery->iRequestStatus = CIrisQuery::ERequestCompleted;
					(*aQuery->iCallback.Get())(aQuery, (*aQuery->iStationNumber), (*aQuery->iServiceName), CIrisQuery::ERequestCompleted, (*&kFormatRequestCompleted()), (*&nextBus), (*&subSequentBus));
					}
				}
			else break;
    		}
		
		// =========

		if(iIrisInitalizationCycle && aQuery == iIrisInitializationPilotService)
			{
			iIrisInitalizationCycle = EFalse;
			for(TInt i = 0 ; i < iIrisQueries.Count() ; ++i)
				if(iIrisQueries[i]->iRequestStatus == CIrisQuery::ERequestPendingInitialization)
					SubmitL(iIrisQueries[i]);
			}
		
		if(AllRequestsCompleted())
			{
			for(TInt i = 0 ; i < iIrisQueries.Count() ; ++i)
				if(iIrisQueries[i]->iRequestStatus == CIrisQuery::ERequestPending)
					{
					iIrisQueries[i]->iRequestStatus = CIrisQuery::ERequestUnavailable;
					(*iIrisQueries[i]->iCallback.Get())(iIrisQueries[i], (*iIrisQueries[i]->iStationNumber), (*iIrisQueries[i]->iServiceName), CIrisQuery::ERequestUnavailable, (*&kFormatRequestUnavailable()), (*&KNullDesC8()), (*&KNullDesC8()));	
					}
			}
		
		}
	else 
		{
		if(iIrisInitalizationCycle && aQuery == iIrisInitializationPilotService)
			{
			iIrisInitalizationCycle = EFalse;
			for(TInt i = 0 ; i < iIrisQueries.Count() ; ++i)
				if(iIrisQueries[i]->iRequestStatus == CIrisQuery::ERequestPendingInitialization)
					{
					iIrisQueries[i]->iRequestStatus = CIrisQuery::ERequestError;
					(*iIrisQueries[i]->iCallback.Get())(iIrisQueries[i], (*iIrisQueries[i]->iStationNumber), (*iIrisQueries[i]->iServiceName), CIrisQuery::ERequestError, (*&kFormatRequestBlocked()), (*&KNullDesC8()), (*&KNullDesC8()));
					}
			}
		else
			{
			aQuery->iRequestStatus = CIrisQuery::ERequestError;
			(*aQuery->iCallback.Get())(aQuery, (*aQuery->iStationNumber), (*aQuery->iServiceName), CIrisQuery::ERequestError, (*&kFormatRequestBlocked()), (*&KNullDesC8()), (*&KNullDesC8()));
			}
		}
	}
	
	aTransaction.Cancel();
	aTransaction.Close(); // note: if a panic is raised before reaching this line, MHFRunError will close the transaction
	}

void CIrisSession::ReceivedIrisCaptchaAnswerL(RHTTPTransaction aTransaction, THTTPEvent aEvent, TInt aLastError, TPtrC8 aBuf)
	{
	TFunTrace funTrace(__PRETTY_FUNCTION__);
	iIrisTimeoutTimerHelper->Cancel();
	iIrisCaptchaTransaction = RHTTPTransaction();
	iIrisStatusCode = aTransaction.Response().StatusCode();
	if(aEvent.iStatus != THTTPEvent::ESucceeded || iIrisStatusCode != 200)
		User::Leave(aLastError < 0 ? aLastError : KErrAbort);

	if(iIrisCaptchaDecoderTarget.Get()) iIrisCaptchaDecoderTarget->Cancel();
	iIrisCaptchaDecoder = CImageDecoder::DataNewL(CCoeEnv::Static()->FsSession(), iIrisCaptchaTransactionTarget->Body()); // a bit dangerous...
	iIrisCaptchaBitmap = new(ELeave)CFbsBitmap(); 
	iIrisCaptchaBitmap->Create(iIrisCaptchaDecoder->FrameInfo(0).iOverallSizeInPixels,iIrisCaptchaDecoder->FrameInfo(0).iFrameDisplayMode);		
	iIrisCaptchaDecoderTarget = new (ELeave) scalp::CActiveTarget(
			scalp::MakeFunctionL ( scalp::Bind(&CImageDecoder::Cancel, iIrisCaptchaDecoder.Get()) ),
			scalp::MakeFunctionL ( scalp::Bind(&CIrisSession::IrisTransactionError, this, iIrisInitializationPilotService, scalp::Free1, RHTTPTransaction()) )
			);
	iIrisCaptchaDecoderTarget->AppendRunL(
			scalp::MakeFunctionL ( scalp::Bind(&CIrisSession::IrisCaptchaImageDecoded, this) )
	);
	iIrisCaptchaDecoder->Convert(&iIrisCaptchaDecoderTarget->iStatus, *iIrisCaptchaBitmap);
	iIrisCaptchaDecoderTarget->SetActive();
	iIrisInitializationPilotService->iRequestStatus = CIrisQuery::ERequestPendingInitialization;
	(*iIrisInitializationPilotService->iCallback.Get())(iIrisInitializationPilotService, (*iIrisInitializationPilotService->iStationNumber), (*iIrisInitializationPilotService->iServiceName), CIrisQuery::ERequestPendingInitialization, (*&kFormatSolvingCaptcha()), (*&KNullDesC8()), (*&KNullDesC8()));
	
	aTransaction.Cancel();
	aTransaction.Close(); // note: if a panic is raised before reaching this line, MHFRunError will close the transaction
	}

#define KAknSplitInputEnabled   0x2001E2C0
#define KAknSplitInputDisabled  0x2001E2C1

struct CIrisCaptchaDialog : public CAknDialog
	{
	TInt& iCaptcha;
	TBool iAknSplitInputEnabled;
	CIrisCaptchaDialog(TInt& aCaptcha) : iCaptcha(aCaptcha), iAknSplitInputEnabled(EFalse) {}
    virtual TBool OkToExitL(TInt aButtonId)
    	{
    	TFunTrace funTrace(__PRETTY_FUNCTION__);
    	CAknQueryControl* control = static_cast<CAknQueryControl*>(Control(2));
    	CAknIntegerEdwin* captchaEditor = (CAknIntegerEdwin*)control->ControlByLayoutOrNull(ENumberLayout);
    	captchaEditor->GetTextAsInteger(iCaptcha);
    	return CEikDialog::OkToExitL(aButtonId);
    	}
    virtual void SetSizeAndPosition(const TSize& aSize)
    	{
    	CAknDialog::SetSizeAndPosition(aSize);
    	
    	if(iAknSplitInputEnabled)
    		{
			SetPosition(
					TPoint(
							Position().iX,0
							)
						);
			}
    	}
    virtual void HandleResourceChange(TInt aType)
    	{
    	TFunTrace funTrace(__PRETTY_FUNCTION__);
    	if ( aType == KAknSplitInputEnabled )
    		iAknSplitInputEnabled = ETrue;
    	else if ( aType == KAknSplitInputDisabled )
    		iAknSplitInputEnabled = EFalse;
    	CAknDialog::HandleResourceChange(aType);
    	}
    
	};


struct CIrisCaptchaDialog2 : public CAknNumberQueryDialog
	{
	CIrisCaptchaDialog2(TInt& aNumber, const TTone& aTone) : CAknNumberQueryDialog(aNumber, aTone) { }
	virtual void SetSizeAndPosition(const TSize& aSize)
		{
		/*
		CAknNumberQueryDialog::SetSizeAndPosition(aSize);
		CEikImage* captchaImage = (CEikImage*)Control(1);
		SetSize(TSize(aSize.iWidth, aSize.iHeight + captchaImage->Size().iHeight));
		SetPosition( Position() - TPoint(0, captchaImage->Size().iHeight) );
		*/
		CAknDialog::SetSizeAndPosition( aSize );
		TRect cRect = ((CAknAppUi*)CCoeEnv::Static()->AppUi())->ClientRect();
		TRect rect = Rect();
		//SetExtent(TPoint(Position().iX, cRect.iBr.iY - rect.Height()), rect.Size());
		}
	};


void CIrisSession::IrisCaptchaImageDecoded()
	{
	TFunTrace funTrace(__PRETTY_FUNCTION__);
	if(iIrisCaptchaDecoderTarget->iStatus == KErrNone)
		{
		if(iIrisCaptchaBitmapScalerTarget.Get()) iIrisCaptchaBitmapScalerTarget->Cancel();
		iIrisCaptchaBitmapScaler = CBitmapScaler::NewL();
		iIrisCaptchaBitmapScalerTarget = new (ELeave) scalp::CActiveTarget (
				scalp::MakeFunctionL ( scalp::Bind(&CBitmapScaler::Cancel, iIrisCaptchaBitmapScaler.Get()) ),
				scalp::MakeFunctionL ( scalp::Bind(&CIrisSession::IrisTransactionError, this, iIrisInitializationPilotService, scalp::Free1, RHTTPTransaction()) )
				);
		TSize screenSize = CEikonEnv::Static()->ScreenDevice()->SizeInPixels();
		iIrisCaptchaBitmapScaler->Scale(&iIrisCaptchaBitmapScalerTarget->iStatus, *iIrisCaptchaBitmap,
				TSize(
						screenSize.iWidth/2,
						screenSize.iHeight/2
						)
				);
		iIrisCaptchaBitmapScalerTarget->AppendRunL(
				scalp::MakeFunctionL ( scalp::Bind(&CIrisSession::IrisCaptchaImageScaled, this) )
		);
		iIrisCaptchaBitmapScalerTarget->SetActive();
		}
	else if(iIrisCaptchaDecoderTarget->iStatus != KErrCancel)
		User::Leave(iIrisCaptchaDecoderTarget->iStatus.Int());
	}

void CIrisSession::HandleResourceChange(TInt aType)
	{
	if(iIrisCaptchaDialog)
		iIrisCaptchaDialog->HandleResourceChange(aType);
	}



void CIrisSession::IrisCaptchaImageScaled()
	{
	TFunTrace funTrace(__PRETTY_FUNCTION__);
	
	if(iIrisCaptchaBitmapScalerTarget->iStatus == KErrNone)
		{
		
		TInt button;
		{
		iIrisCaptcha = 0;
		CAknNumberQueryDialog* captchaDialog = new (ELeave) CIrisCaptchaDialog2(iIrisCaptcha, CAknQueryDialog::ENoTone);
		captchaDialog->PrepareLC(R_CAPTCHA_DIALOG);
		CEikImage* captchaImage = (CEikImage*)captchaDialog->Control(1);
		captchaImage->SetSize(iIrisCaptchaBitmap->SizeInPixels());
		delete captchaImage->Bitmap();
		captchaImage->SetBitmap(iIrisCaptchaBitmap.Unmanage());
		iIrisCaptchaDialog = captchaDialog;
		button = captchaDialog->RunLD();
		iIrisCaptchaDialog = NULL;
		}
	
		if(button == EAknSoftkeyOk)
		{
			TBuf8<1024> url;
			url.Format(_L8("http://www.sbstransit.com.sg/mobileiris/%S/%S"), iIrisToken, iIrisCaptchaActionPage);
			if(iIrisInitializationPilotService->iServiceTransaction != RHTTPTransaction())
				{
				iIrisInitializationPilotService->iServiceTransaction.Cancel();
				iIrisInitializationPilotService->iServiceTransaction.Close();
				}
			delete iIrisInitializationPilotService->iServiceTransactionTarget;
			iIrisInitializationPilotService->iServiceTransactionTarget = CHTTPTransactionTarget::NewL();
			iIrisInitializationPilotService->iServiceTransactionTarget->SetRun( scalp::MakeFunctionL( scalp::Bind(&CIrisSession::ReceivedIrisMobresultAnswerL, this, iIrisInitializationPilotService, scalp::Free1, scalp::Free2, scalp::Free3, scalp::Free4) ) );
			iIrisInitializationPilotService->iServiceTransactionTarget->SetRunBodyData(NULL);
			iIrisInitializationPilotService->iServiceTransactionTarget->SetRunError( scalp::MakeFunctionL( scalp::Bind(&CIrisSession::IrisTransactionError, this, iIrisInitializationPilotService, scalp::Free1, scalp::Free2) ) );			
			iIrisInitializationPilotService->iServiceTransaction = RHTTPSessionOpenTransactionL(iHTTPSession, url, *iIrisInitializationPilotService->iServiceTransactionTarget, HTTP::EPOST);
			if(iIrisRlStickyKey)
				RHTTPRequestSetCookie(iHTTPSession, iIrisInitializationPilotService->iServiceTransaction.Request(), _L8("rl-sticky-key"), *iIrisRlStickyKey);
			RHTTPRequestSetHeaderL(iHTTPSession, iIrisInitializationPilotService->iServiceTransaction.Request(), HTTP::EContentType, _L8("application/x-www-form-urlencoded"));
			TBuf8<1024> referer;
			referer.Format(_L8("http://www.sbstransit.com.sg/mobileiris/%S/validation_page.aspx"), iIrisToken);
			RHTTPRequestSetHeaderL(iHTTPSession, iIrisInitializationPilotService->iServiceTransaction.Request(), HTTP::EReferer, referer);
			iIrisInitializationPilotService->iServiceTransaction.Request().SetBody(*iIrisCaptchaTransactionSource);
			TBuf8<1024> postData;
			postData.Format(_L8("__ET=&txt_code=%0*d&cmd_submit=Submit"), 3, iIrisCaptcha);
			iIrisCaptchaTransactionSource->SetPostDataL(postData);
			{
				// faster without pipelining
				RStringPool strP = iHTTPSession.StringPool();
				const TStringTable& stringTable = RHTTPSession::GetTable();
				RStringF httpPipelining = strP.StringF( HTTP::EHttpPipelining, stringTable );
				THTTPHdrVal disablePipelining = strP.StringF( HTTP::EDisablePipelining, stringTable );
				iIrisInitializationPilotService->iServiceTransaction.PropertySet().RemoveProperty( httpPipelining );
				iIrisInitializationPilotService->iServiceTransaction.PropertySet().SetPropertyL( httpPipelining, disablePipelining );
			}
			
			iIrisInitializationPilotService->iServiceTransaction.SubmitL();
			iIrisTimeoutTimerHelper->Cancel();
			iIrisTimeoutTimer.After(iIrisTimeoutTimerHelper->iStatus, kIrisTimeout);
			iIrisTimeoutTimerHelper->SetActive(this, &iIrisTimeoutTimer);
			iIrisInitializationPilotService->iRequestStatus = CIrisQuery::ERequestPendingInitialization;
			(*iIrisInitializationPilotService->iCallback.Get())(iIrisInitializationPilotService, (*iIrisInitializationPilotService->iStationNumber), (*iIrisInitializationPilotService->iServiceName), CIrisQuery::ERequestPendingInitialization, (*&kFormatRequestSubmittingCaptcha()), (*&KNullDesC8()), (*&KNullDesC8()));
			SubmitCrowdIrisTokenUpdateRequestL();
		}
		else User::Leave(KErrCancel);
	}
	else if(iIrisCaptchaBitmapScalerTarget->iStatus != KErrCancel)
		User::Leave(iIrisCaptchaBitmapScalerTarget->iStatus.Int());
}



void CIrisSession::SubmitL(CIrisQuery* aQuery)
{
TFunTrace funTrace(__PRETTY_FUNCTION__);

	TTime currentTime;
	currentTime.HomeTime();
	TTimeIntervalSeconds secondsFromLastFailureIrisApi, secondsFromLastFailureCrowdIrisToken;

	if(currentTime.SecondsFrom(iLastFailureIrisApi, secondsFromLastFailureIrisApi) == KErrOverflow ||
			secondsFromLastFailureIrisApi >= TTimeIntervalSeconds(30)
		)
		SubmitIrisApiRequestL(aQuery);
	else if(iIrisInitalizationCycle)
		{
		aQuery->iRequestStatus = CIrisQuery::ERequestPendingInitialization;
		(*aQuery->iCallback.Get())(aQuery, (*aQuery->iStationNumber), (*aQuery->iServiceName), CIrisQuery::ERequestPendingInitialization, (*&kFormatRequestPendingInitialization()), (*&KNullDesC8()), (*&KNullDesC8()));			
		}
	else if(iIrisToken == NULL)
		{
		iIrisInitalizationCycle = ETrue;
		iIrisInitializationPilotService = aQuery;
		// disable crowd token: crowd token is blocked by SBS transit now
		if(false && currentTime.SecondsFrom(iLastFailureCrowdIrisToken, secondsFromLastFailureCrowdIrisToken) == KErrOverflow ||
				secondsFromLastFailureCrowdIrisToken >= TTimeIntervalSeconds(30)
			)
			SubmitCrowdIrisTokenRequestL(); // we try the crowd token first
		else	
			SubmitIrisTokenRequestL();

		}
	else
		{
		SubmitIrisMobresultRequestL(aQuery);
		}
}


void CIrisSession::MActiveHelperCallbackRunL(CActiveHelper<RTimer*>* aActiveHelper, RTimer* aTimer)
{
TFunTrace funTrace(__PRETTY_FUNCTION__);

if(aActiveHelper->iStatus != KErrNone) return;

	if(aActiveHelper == iCrowdIrisTimeoutTimerHelper)
	{
		iLastFailureCrowdIrisToken.HomeTime();
		CancelAllIrisRequestsL();
		for(TInt i = 0 ; i < iIrisQueries.Count() ; ++i)
			if( (iIrisQueries[i]->iRequestStatus == CIrisQuery::ERequestPending || iIrisQueries[i]->iRequestStatus == CIrisQuery::ERequestPendingInitialization))
				SubmitL(iIrisQueries[i]);
	}
	else if(aActiveHelper == iIrisTimeoutTimerHelper)
		{
		CancelAllIrisRequestsL();
		//delete iIrisToken; // keep the token???? for now: yes
		//iIrisToken = NULL;
		for(TInt i = 0 ; i < iIrisQueries.Count() ; ++i)
			if( (iIrisQueries[i]->iRequestStatus == CIrisQuery::ERequestPending || iIrisQueries[i]->iRequestStatus == CIrisQuery::ERequestPendingInitialization))
				SubmitL(iIrisQueries[i]);
		}
}

TInt CIrisSession::MActiveHelperCallbackRunError(CActiveHelper<RTimer*>* aActiveHelper, RTimer* aTimer, TInt aError)
{
TFunTrace funTrace(__PRETTY_FUNCTION__);
}

void CIrisSession::MActiveHelperCallbackDoCancel(CActiveHelper<RTimer*>* aActiveHelper, RTimer* aTimer)
{
TFunTrace funTrace(__PRETTY_FUNCTION__);
	aTimer->Cancel();
}


CIrisQuery::CIrisQuery(CIrisSession* aSession, const TDesC8& aServiceName, const TDesC8& aStationNumber, TInt aStationInterchange, TCallback* aCallback)
: iSession(aSession), iServiceName(NULL), iStationNumber(NULL), iCallback(aCallback)
	{
	TFunTrace funTrace(__PRETTY_FUNCTION__);
	iServiceName = aServiceName.AllocLC();
	iStationNumber = aStationNumber.AllocLC();
	iStationInterchange = aStationInterchange;
	CleanupStack::Pop(2);
	iSession->iIrisQueries.Append(this);
	}

void CIrisQuery::SubmitL()
	{
	TFunTrace funTrace(__PRETTY_FUNCTION__);
	iSession->SubmitL(this);
	}
void CIrisQuery::Cancel()
	{
	TFunTrace funTrace(__PRETTY_FUNCTION__);
	iSession->Cancel(this);
	}

CIrisQuery::~CIrisQuery()
	{
	TFunTrace funTrace(__PRETTY_FUNCTION__);
	TRAPD(err, Cancel()); // ignore leaves
	delete iServiceName;
	delete iStationNumber;
	delete iServiceTransactionTarget;
	delete iServiceTransactionSource;
	TInt i;
	for(i = 0 ; i < iSession->iIrisQueries.Count() && iSession->iIrisQueries[i] != this ; ++i);
	if(i < iSession->iIrisQueries.Count())
		iSession->iIrisQueries.Remove(i);
	}


